/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package de.tor.tribes.reportserver.util;

import de.tor.tribes.reportserver.MyVaadinApplication;
import de.tor.tribes.reportserver.PersistenceImpl;
import de.tor.tribes.types.DSBuilding;
import de.tor.tribes.types.DSUnit;
import de.tor.tribes.types.ParserConfiguration;
import de.tor.tribes.types.ParserPattern;
import de.tor.tribes.types.ParserPatternRelation;
import de.tor.tribes.types.ZebraUser;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jdom.Document;
import org.jdom.Element;
import org.lorecraft.phparser.SerializedPhpParser;

/**
 *
 * @author Torridity
 */
public class ZebraInitializer {

    private static LinkedHashMap<String, String> servers = null;
    //private static final String configPath = "H:/Software/DSWorkbench/servers/de81/";

    public static void initialize(MyVaadinApplication pApplication) throws Exception {

//        if (!initializeAdmin(pApplication)) {
//            //already done
//            return;
//        }
        if (initializeAdmin(pApplication)) {
            /*  List<ParserPattern> patterns = pApplication.getPersistence().performQueryForList("SELECT * FROM ParserPatterns", ParserPattern.class);
             if (patterns.isEmpty()) {
             //persist patterns
             for (ParserPattern.PARSER_PATTERN_ID id : ParserPattern.PARSER_PATTERN_ID.values()) {
             ParserPattern p = new ParserPattern();
             p.setPatternName(id);
             pApplication.getPersistence().persist(p);
             }
             }*/


            loadServers(pApplication);
        }

        for (ParserPattern.PARSER_PATTERN_ID id : ParserPattern.PARSER_PATTERN_ID.values()) {
            ParserPattern pattern = pApplication.getPersistence().performQueryForSingleValue("SELECT * FROM ParserPatterns WHERE patternname='" + id.toString() + "'", ParserPattern.class);
            if (pattern == null) {
                ParserPattern p = new ParserPattern();
                p.setPatternName(id);
                pApplication.getPersistence().persist(p);
            }
        }

//        String unitConfig = "H:/Software/DSWorkbench/servers/de76/units.xml";
//        if (!new File(unitConfig).exists()) {
//            unitConfig = "/home/torridity/Zebra/units.xml";
//        }
//        try {
//            Document d = JaxenUtils.getDocument(new File(unitConfig));
//            List<Element> l = (List<Element>) JaxenUtils.getNodes(d, "/config/*");
//            for (Element e : l) {
//                DSUnit unit = loadUnit(e);
//                if (unit != null && unit.getPlainName() != null) {
//                    pApplication.getPersistence().persist(unit);
//                }
//            }
//        } catch (Exception outer) {
//            Logger.getLogger(ZebraInitializer.class.getName()).log(Level.SEVERE, "Failed to initialize units", outer);
//        }
//
//        String buildingConfig = configPath + "buildings.xml";
//        if (!new File(buildingConfig).exists()) {
//            buildingConfig = "/home/torridity/Zebra/buildings.xml";
//        }
//        try {
//            Document d = JaxenUtils.getDocument(new File(buildingConfig));
//            List<Element> l = (List<Element>) JaxenUtils.getNodes(d, "/config/*");
//            for (Element e : l) {
//                DSBuilding building = loadBuilding(e);
//                if (building != null && building.getPlainName() != null) {
//                    pApplication.getPersistence().persist(building);
//                }
//            }
//        } catch (Exception outer) {
//            Logger.getLogger(ZebraInitializer.class.getName()).log(Level.SEVERE, "Failed to initialize buildings", outer);
//        }
//

    }

    public static void loadServers(MyVaadinApplication pApplication) throws Exception {
        URLConnection con = new URL("http://www.die-staemme.de/backend/get_servers.php").openConnection();
        InputStream isr = con.getInputStream();
        int bytes = 0;
        byte[] data = new byte[1024];
        ByteArrayOutputStream result = new ByteArrayOutputStream();
        int sum = 0;
        while (bytes != -1) {
            if (bytes != -1) {
                result.write(data, 0, bytes);
            }

            bytes = isr.read(data);
            sum += bytes;
            if (sum % 500 == 0) {
                try {
                    Thread.sleep(50);
                } catch (Exception e) {
                }
            }
        }
        //get servers
        SerializedPhpParser serializedPhpParser = new SerializedPhpParser(result.toString());
        Object obj = serializedPhpParser.parse();
        servers = (LinkedHashMap<String, String>) obj;
        Set<Entry<String, String>> entries = servers.entrySet();
        //get available entries
        List<DSUnit> existingUnits = pApplication.getPersistence().getUnits();
        List<String> plainUnitNames = new LinkedList<String>();
        List<DSBuilding> existingBuildings = pApplication.getPersistence().getBuildings();
        List<String> plainBuildingNames = new LinkedList<String>();
        for (DSUnit unit : existingUnits) {
            plainUnitNames.add(unit.getPlainName());
        }
        for (DSBuilding building : existingBuildings) {
            plainBuildingNames.add(building.getPlainName());
        }

        for (Entry<String, String> entry : entries) {
            String id = entry.getKey();
            //check units
            List<DSUnit> units = parseUnits(entry.getValue());
            String unitsForServer = "";
            for (DSUnit unit : units) {
                //check if we have the unit
                if (!plainUnitNames.contains(unit.getPlainName())) {
                    //we don't, add it
                    pApplication.getPersistence().persist(unit);
                    plainUnitNames.add(unit.getPlainName());
                }
                unitsForServer += unit.getPlainName() + ",";
            }

            if (unitsForServer.length() > 2) {
                unitsForServer = unitsForServer.substring(0, unitsForServer.length() - 1);
                ParserConfiguration config = pApplication.getPersistence().getParserConfiguration(id);

                if (!pApplication.getPersistence().contains(config)) {
                    //build pattern
                    config.setPatternValue(ParserPattern.PARSER_PATTERN_ID.SUPPORTED_UNITS, unitsForServer, pApplication.getPersistence());
                    pApplication.getPersistence().persist(config);
                }
            }


            List<DSBuilding> buildings = parseBuildings(entry.getValue());
            for (DSBuilding building : buildings) {
                //check if we have the unit
                if (!plainBuildingNames.contains(building.getPlainName())) {
                    //we don't, add it
                    pApplication.getPersistence().persist(building);
                }
            }
            //break;
        }
    }

    public static List<DSUnit> parseUnits(String pServerUrl) throws Exception {
        List<DSUnit> result = new LinkedList<DSUnit>();
        try {
            // Document d = JaxenUtils.getDocument(UnitManager.class.getResourceAsStream("/res/servers/units_" + pServerID + ".xml"));
            URLConnection con = new URL(pServerUrl + "/interface.php?func=get_unit_info").openConnection();
            Document d = JaxenUtils.getDocument(con.getInputStream());
            List<Element> l = JaxenUtils.getNodes(d, "/config/*");
            for (Element e : l) {
                try {
                    result.add(loadUnit(e));
                } catch (Exception inner) {
                    inner.printStackTrace();
                }
            }
        } catch (Exception outer) {
            throw new Exception("Failed to load units for server '" + pServerUrl + "'", outer);
        }
        return result;
    }

    private static List<DSBuilding> parseBuildings(String pServerUrl) throws Exception {
        List<DSBuilding> result = new LinkedList<DSBuilding>();
        try {
            // Document d = JaxenUtils.getDocument(UnitManager.class.getResourceAsStream("/res/servers/units_" + pServerID + ".xml"));
            URLConnection con = new URL(pServerUrl + "/interface.php?func=get_building_info").openConnection();
            Document d = JaxenUtils.getDocument(con.getInputStream());
            List<Element> l = JaxenUtils.getNodes(d, "/config/*");
            for (Element e : l) {
                try {
                    result.add(loadBuilding(e));
                } catch (Exception inner) {
                    inner.printStackTrace();
                }
            }
        } catch (Exception outer) {
            throw new Exception("Failed to load buildings for server '" + pServerUrl + "'", outer);
        }
        return result;
    }

    private static DSUnit loadUnit(Element pElement) throws Exception {
        try {
            DSUnit unit = new DSUnit();
            unit.setPlainName(pElement.getName());
            if (pElement.getName().equals("spear")) {
                unit.setName("Speerträger");
            } else if (pElement.getName().equals("sword")) {
                unit.setName("Schwertkämpfer");
            } else if (pElement.getName().equals("axe")) {
                unit.setName("Axtkämpfer");
            } else if (pElement.getName().equals("archer")) {
                unit.setName("Bogenschütze");
            } else if (pElement.getName().equals("spy")) {
                unit.setName("Späher");
            } else if (pElement.getName().equals("light")) {
                unit.setName("Leichte Kavallerie");
            } else if (pElement.getName().equals("marcher")) {
                unit.setName("Berittener Bogenschütze");
            } else if (pElement.getName().equals("heavy")) {
                unit.setName("Schwere Kavallerie");
            } else if (pElement.getName().equals("ram")) {
                unit.setName("Ramme");
            } else if (pElement.getName().equals("catapult")) {
                unit.setName("Katapult");
            } else if (pElement.getName().equals("knight")) {
                unit.setName("Paladin");
            } else if (pElement.getName().equals("snob")) {
                unit.setName("Adelsgeschlecht");
            } else if (pElement.getName().equals("militia")) {
                unit.setName("Miliz");
            } else {
                unit.setName("Unbekannt (" + pElement.getName() + ")");
            }

            unit.setWood(Double.parseDouble(pElement.getChild("wood").getText()));
            unit.setStone(Double.parseDouble(pElement.getChild("stone").getText()));
            unit.setIron(Double.parseDouble(pElement.getChild("iron").getText()));
            unit.setPop(Double.parseDouble(pElement.getChild("pop").getText()));
            unit.setSpeed(Double.parseDouble(pElement.getChild("speed").getText()));
            unit.setAttack(Double.parseDouble(pElement.getChild("attack").getText()));
            unit.setDefense(Double.parseDouble(pElement.getChild("defense").getText()));
            unit.setDefenseCavalry(Double.parseDouble(pElement.getChild("defense_cavalry").getText()));
            unit.setDefenseArcher(Double.parseDouble(pElement.getChild("defense_archer").getText()));
            unit.setCarry(Double.parseDouble(pElement.getChild("carry").getText()));
            unit.setBuildTime(Double.parseDouble(pElement.getChild("build_time").getText()));
            return unit;
        } catch (Exception e) {
            throw new Exception("Failed to read unit '" + pElement.getName() + "'", e);
        }
    }

    private static DSBuilding loadBuilding(Element pElement) throws Exception {
        try {
            DSBuilding building = new DSBuilding();
            building.setPlainName(pElement.getName());
            if (pElement.getName().equals("main")) {
                building.setName("Hauptgebäude");
            } else if (pElement.getName().equals("barracks")) {
                building.setName("Kaserne");
            } else if (pElement.getName().equals("stable")) {
                building.setName("Stall");
            } else if (pElement.getName().equals("garage")) {
                building.setName("Werkstatt");
            } else if (pElement.getName().equals("church")) {
                building.setName("Kirche");
            } else if (pElement.getName().equals("church_f")) {
                building.setName("Erste Kirche");
            } else if (pElement.getName().equals("snob")) {
                building.setName("Adelshof");
            } else if (pElement.getName().equals("smith")) {
                building.setName("Schmiede");
            } else if (pElement.getName().equals("place")) {
                building.setName("Versammlungsplatz");
            } else if (pElement.getName().equals("market")) {
                building.setName("Marktplatz");
            } else if (pElement.getName().equals("wood")) {
                building.setName("Holzfäller");
            } else if (pElement.getName().equals("stone")) {
                building.setName("Lehmgrube");
            } else if (pElement.getName().equals("iron")) {
                building.setName("Eisenmine");
            } else if (pElement.getName().equals("farm")) {
                building.setName("Bauernhof");
            } else if (pElement.getName().equals("storage")) {
                building.setName("Speicher");
            } else if (pElement.getName().equals("hide")) {
                building.setName("Versteck");
            } else if (pElement.getName().equals("wall")) {
                building.setName("Wall");
            } else {
                building.setName("Unbekannt (" + pElement.getName() + ")");
            }

            building.setWood(Short.parseShort(pElement.getChild("wood").getText()));
            building.setStone(Short.parseShort(pElement.getChild("stone").getText()));
            building.setIron(Short.parseShort(pElement.getChild("iron").getText()));
            building.setPop(Short.parseShort(pElement.getChild("pop").getText()));
            building.setMin_level(Short.parseShort(pElement.getChild("min_level").getText()));
            building.setMax_level(Short.parseShort(pElement.getChild("max_level").getText()));
            building.setBuild_time(Double.parseDouble(pElement.getChild("build_time").getText()));
            building.setBuild_time_factor(Double.parseDouble(pElement.getChild("build_time_factor").getText()));
            building.setIron_factor(Double.parseDouble(pElement.getChild("iron_factor").getText()));
            building.setWood_factor(Double.parseDouble(pElement.getChild("wood_factor").getText()));
            building.setStone_factor(Double.parseDouble(pElement.getChild("stone_factor").getText()));
            building.setPop_factor(Double.parseDouble(pElement.getChild("pop_factor").getText()));
            return building;
        } catch (Exception e) {
            throw new Exception("Failed to read building '" + pElement.getName() + "'", e);
        }
    }

    private static boolean initializeAdmin(MyVaadinApplication pApplication) {
        if (pApplication.getPersistence().findUserByName("test") == null) {
            ZebraUser tester = new ZebraUser();
            tester.setName("test");
            tester.setPlainPassword("test");
            pApplication.getPersistence().persistUser(tester);
            return true;
        }
        return false;
    }
}
